import fastapi
from fastapi import FastAPI
import uvicorn
from dataclasses import dataclass
from typing import Optional
from pydantic import BaseModel
from fastapi import Query, Body, status
from pydantic import validator, Field
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
from pydantic.error_wrappers import ValidationError
import pydantic
from fastapi import Depends
from fastapi.requests import Request
import datetime

from fastapi.responses import JSONResponse
from pydantic.json import ENCODERS_BY_TYPE

ENCODERS_BY_TYPE[datetime.datetime] = lambda date_obj: date_obj.strftime("%Y-%m-%d %H:%M:%S")


async def not_found(request: Request, exc):
    return error_json('404 not fount', url=str(request.url), method=request.method)


app = FastAPI(exception_handlers={
    404: not_found
}
)

import datetime


def success_json(data, **kwargs):
    return JSONResponse(content={'data': data, **kwargs}, status_code=status.HTTP_200_OK)


def error_json(errmsg, status_code=status.HTTP_400_BAD_REQUEST, **kwargs):
    return JSONResponse(content={'errmsg': errmsg, **kwargs}, status_code=status_code)


class ParamModel(object):
    def __init__(self, day: str):
        self.day_str: str = day
        try:
            self.day: datetime.datetime = datetime.datetime.strptime(day, '%Y-%m-%d')
        except Exception:
            raise fastapi.HTTPException(fastapi.status.HTTP_403_FORBIDDEN, detail='参数错误')


class MyDay(BaseModel):
    day: datetime.datetime = None

    @validator('day', pre=True)
    def v_day2(cls, value):
        print(value, 'aaasdsd', type(value))
        return value + ' 00:00'

    @validator('day')
    def v_day(cls, value):
        print(value, 'sdsd', type(value))
        return value


def depend_day(day) -> MyDay:
    return MyDay(day=day)


# 重写参数校验失败的异常
@app.exception_handler(ValidationError)
async def handle_validation_error(request, exc):
    return JSONResponse(
        status_code=418,
        content={"message": f"参数错误 {str(exc)}"},
    )


"""
common: Model这种模式的都是从json body里获取
如果json要求传递的参数只有一个，那么一般要加上 embed=True，因为如果body json参数只有一个，会认为整个body就是value
如果要把请求参数封装在Depends，那么只能使用普通类__init__(Body(), Query())的模式

def hello(common: pydantic.BaseModel = Depends()) 这种语法没有错误，但是逻辑错误，因为Depends读取的是class的__init__的参数
这样书写会导致失效
"""


# http get ':9999/test1'
# http get ':9999/test1?age1=1' age2=2
# http get ':9999/test1?age1=1' age1=99 age2=4 common:='{"size": 10}'

@app.get('/test1')
async def test1(data: ParamModel = Depends()):
    import decimal
    return {
        'day': data.day,
        'd': decimal.Decimal(23)
    }


@app.get('/test2')
async def test2(data: MyDay = Depends(lambda day: MyDay(day=day))):
    print(data.day)
    import decimal
    return {
        'day': data.day,
        'd': decimal.Decimal(23)
    }


@app.get('/error')
async def error():
    return error_json('参数错误哦', status.HTTP_422_UNPROCESSABLE_ENTITY)


@app.get('/success')
async def success():
    return success_json({'list': [a for a in range(10)]})


if __name__ == '__main__':
    uvicorn.run('__main__:app', port=9999, reload=True)
